package demo.java.lang.management;

import com.alibaba.fastjson.JSONObject;
import demo.java.time.DateTimeDemo;
import demo.javax.management.ObjectNameDemo;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * Java 虚拟机的运行时系统的管理接口。
 * <p>
 * Java 虚拟机具有此接口的实现类的单一实例。实现此接口的实例是一个 MXBean，它可以通过调用
 * ManagementFactory.getRuntimeMXBean() 方法或从平台 MBeanServer 方法获得。
 * <p>
 * 在 MBeanServer 中唯一标识运行时系统的 MXBean 的 ObjectName 为：java.lang:type=Runtime
 * <p>
 * 此接口定义了几种便捷的方法，可用于访问有关 Java 虚拟机的系统属性。
 */
public class RuntimeMXBeanDemo {

    private static Logger logger = LoggerFactory.getLogger(RuntimeMXBeanDemo.class);

    @Test
    public void testRuntimeMXbean() {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        ObjectNameDemo.printObjectName(runtimeMXBean.getObjectName());

        printRuntimeMXBean(runtimeMXBean);

        String rumtimeMXBeanStr = JSONObject.toJSONString(runtimeMXBean);
        logger.info("runtimeMXBean.toJson = {}", rumtimeMXBeanStr);
    }

    /**
     * 返回由引导类加载器 用于搜索类文件的引导类路径。 引导类路径中的多个路径由平台（Java 虚拟机在其上运行）的路径分隔符字符进行分隔。
     * <p>
     * Java 虚拟机实现可能不支持引导类加载器用于搜索类文件的引导类路径机制。isBootClassPathSupported() 方法可用于确定 Java
     * 虚拟机是否支持此方法。
     */
    @Test
    public void getBootClassPath() {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        String bootClassPath = runtimeMXBean.getBootClassPath();
        logger.info("bootClassPath = {}", bootClassPath);
        for (String info : bootClassPath.split(";")) {
            logger.info(info);
        }
    }

    /**
     * 返回系统类加载器 用于搜索类文件的 Java 类路径。此方法等效于 System.getProperty("java.class.path")。
     */
    @Test
    public void getClassPath() {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        String classPath = runtimeMXBean.getClassPath();
        logger.info("classPath = {}", classPath);
        for (String info : classPath.split(";")) {
            logger.info(info);
        }
    }

    /**
     * 返回传递给 Java 虚拟机的输入变量，其中不包括传递给 main 方法的变量。
     * <p>
     * 如果没有传递给 Java 虚拟机的输入变量，则此方法将返回一个空列表。 有些 Java 虚拟机实现可能从多个不同源获取输入变量：例如，从启动 Java
     * 虚拟机的应用程序传递的变量，如“java”命令、环境变量、配置文件等。
     * <p>
     * 通常，并非所有的“java”命令的命令行选项都会传递给 Java 虚拟机。因此，返回的输入变量中可能不包括所有命令行选项。
     */
    @Test
    public void getInputArguments() {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        List<String> inputArguments = runtimeMXBean.getInputArguments();
        logger.info("inputArguments = {}", inputArguments);
        for (String info : inputArguments) {
            logger.info(info);
        }
    }

    /**
     * 返回 Java 库路径。此方法等效于 System.getProperty("java.library.path")。
     */
    @Test
    public void getLibraryPath() {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        String libraryPath = runtimeMXBean.getLibraryPath();
        logger.info("libraryPath = {}", libraryPath);
        for (String info : libraryPath.split(";")) {
            logger.info(info);
        }
    }

    /**
     * 返回正在运行的 Java 虚拟机实现的管理接口的规范版本。
     */
    @Test
    public void getManagementSpecVersion() {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        String managementSpecVersion = runtimeMXBean.getManagementSpecVersion();
        logger.info("managementSpecVersion = {}", managementSpecVersion);
    }

    /**
     * 返回表示正在运行的 Java 虚拟机的名称。
     * <p>
     * format: "pid@hostname"
     */
    @Test
    public void getName() {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        String name = runtimeMXBean.getName();
        logger.info("name = {}", name);
    }

    /**
     * 返回 Java 虚拟机规范名称，此方法等效于 System.getProperty("java.vm.specification.name")。
     */
    @Test
    public void getSpecName() {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        String specName = runtimeMXBean.getSpecName();
        logger.info("specName = {}", specName);
    }

    /**
     * 返回所有系统属性的名称和值的映射。
     */
    @Test
    public void getSystemProperties() {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        Map<String, String> systemProperties = runtimeMXBean.getSystemProperties();
        logger.info("systemProperties = {}", systemProperties);
        for (Entry<String, String> entry : systemProperties.entrySet()) {
            logger.info("{}", entry);
        }
    }

    /**
     * 打印RuntimeMXBean
     */
    public static void printRuntimeMXBean(RuntimeMXBean runtimeMXBean) {
        logger.info("RuntimeMXBean = {}", runtimeMXBean);
        // 返回 Java 虚拟机的启动时间（以毫秒为单位）。
        long startTime = runtimeMXBean.getStartTime();
        logger.info("启动时间 ， startTime = {}", DateTimeDemo.toLocalDateTime(startTime));
        // 返回 Java 虚拟机的正常运行时间（以毫秒为单位）。
        long uptime = runtimeMXBean.getUptime();
        logger.info("正常运行时间 , uptime = {} ms.", uptime);
        // 返回 Java 虚拟机实现版本。System.getProperty("java.vm.version")。
        String vmVersion = runtimeMXBean.getVmVersion();
        logger.info("Java 虚拟机实现版本, vmVersion = {}", vmVersion);
        // 返回 Java 虚拟机实现供应商。 System.getProperty("java.vm.vendor")。
        String vmVendor = runtimeMXBean.getVmVendor();
        logger.info("Java 虚拟机实现供应商 , vmVendor = {}", vmVendor);
        // 返回 Java 虚拟机实现名称。此方法等效于 System.getProperty("java.vm.name")。
        String vmName = runtimeMXBean.getVmName();
        logger.info("Java 虚拟机实现名称, vmName = {}", vmName);
        // 返回 Java 虚拟机规范版本。此方法等效于 System.getProperty("java.vm.specification.version")。
        String specVersion = runtimeMXBean.getSpecVersion();
        logger.info(" Java 虚拟机规范版本 , specVersion = {}", specVersion);
        // 返回 Java 虚拟机规范供应商。此方法等效于 System.getProperty("java.vm.specification.vendor")。
        String specVendor = runtimeMXBean.getSpecVendor();
        logger.info("Java 虚拟机规范供应商 , specVendor = {}", specVendor);
        // 测试 Java 虚拟机是否支持由引导类加载器用于搜索类文件的引导类路径机制。
        boolean isBootClassPathSupported = runtimeMXBean.isBootClassPathSupported();
        logger.info("Java 虚拟机是否支持由引导类加载器用于搜索类文件的引导类路径机制, isBootClassPathSupported = {}", isBootClassPathSupported);
    }
}
